package com.yonyougov.devops.cruxcisupport.committest;

import com.google.common.collect.Lists;
import com.yonyougov.devops.cruxcisupport.app.AppDao;
import com.yonyougov.devops.cruxcisupport.app.AppEntity;
import com.yonyougov.devops.cruxcisupport.app.AppService;
import com.yonyougov.devops.cruxcisupport.attachment.AttachmentDao;
import com.yonyougov.devops.cruxcisupport.attachment.AttachmentEntity;
import com.yonyougov.devops.cruxcisupport.attachment.AttachmentService;
import com.yonyougov.devops.cruxcisupport.backupuser.BackupTestUserDao;
import com.yonyougov.devops.cruxcisupport.commitcontext.CommitContextDao;
import com.yonyougov.devops.cruxcisupport.commitcontext.CommitContextEntity;
import com.yonyougov.devops.cruxcisupport.commitcontext.CommitContextService;
import com.yonyougov.devops.cruxcisupport.committest.dto.*;
import com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseCommitTestDto;
import com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseContextRequestDto;
import com.yonyougov.devops.cruxcisupport.committest.vo.*;
import com.yonyougov.devops.cruxcisupport.committrace.CommitTraceDao;
import com.yonyougov.devops.cruxcisupport.committrace.CommitTraceEntity;
import com.yonyougov.devops.cruxcisupport.committrace.CommitTraceService;
import com.yonyougov.devops.cruxcisupport.committrace.dto.CommitTestIdAndStatusDto;
import com.yonyougov.devops.cruxcisupport.committrace.dto.CommitTestIdInStatusInDto;
import com.yonyougov.devops.cruxcisupport.committrace.dto.CommitTraceEntityByInDto;
import com.yonyougov.devops.cruxcisupport.committrace.vo.CommitTraceKeyValueVo;
import com.yonyougov.devops.cruxcisupport.component.UserStore;
import com.yonyougov.devops.cruxcisupport.enums.TestStatusEnum;
import com.yonyougov.devops.cruxcisupport.enums.TestTypeEnum;
import com.yonyougov.devops.cruxcisupport.enums.UserOfficeTypeEnum;
import com.yonyougov.devops.cruxcisupport.role.RoleEntity;
import com.yonyougov.devops.cruxcisupport.subscribe.SubscribeDao;
import com.yonyougov.devops.cruxcisupport.thread.SendCreateOrConfirmMailThread;
import com.yonyougov.devops.cruxcisupport.thread.SendRejectOrPassOrReleaseMailThread;
import com.yonyougov.devops.cruxcisupport.user.UserDao;
import com.yonyougov.devops.cruxcisupport.user.UserEntity;
import com.yonyougov.devops.cruxcisupport.user.UserService;
import com.yonyougov.devops.cruxcisupport.util.*;
import com.yonyougov.devops.cruxcisupport.util.excell.CruxVersionUpBugFixRemarkEntity;
import com.yonyougov.devops.cruxcisupport.util.excell.CruxVersionUpEntity;
import com.yonyougov.devops.cruxcisupport.util.excell.CruxVersionUpNewAddFuncRemarkEntity;
import com.yonyougov.devops.cruxcisupport.util.excell.ExcellUtil;
import com.yonyougov.devops.cruxcisupport.version.VersionDao;
import com.yonyougov.devops.cruxcisupport.version.VersionEntity;
import com.yonyougov.devops.cruxcisupport.version.VersionService;
import com.yonyougov.devops.cruxcisupport.versioninfo.VersionInfoDao;
import com.yonyougov.devops.cruxcisupport.versioninfo.VersionInfoEntity;
import com.yonyougov.devops.fwc.core.dao.BaseDao;
import com.yonyougov.devops.fwc.core.entity.Pagination;
import com.yonyougov.devops.fwc.core.service.impl.BaseServiceImpl;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 提测表服务实现
 */
@Slf4j
@Service
public class CommitTestServiceImpl extends BaseServiceImpl<CommitTestEntity, BigInteger> implements CommitTestService {
    private final CommitTestDao commitTestDao;
    private final CommitTraceDao commitTraceDao;
    private final AttachmentDao attachmentDao;
    private final UserStore userStore;
    private final MailUtils mailUtils;
    private final UserDao userDao;
    private final UserService userService;
    private final VersionDao versionDao;
    private final AppDao appDao;
    private final BackupTestUserDao backupTestUserDao;
    private final SubscribeDao subscribeDao;
    private final CommitContextService commitContextService;
    private final ExcellUtil excellUtil;
    private final CommitContextDao commitContextDao;
    private final VersionInfoDao versionInfoDao;
    private final CommitTraceService commitTraceService;
    private final AttachmentService attachmentService;
    private final AppService appService;
    private final VersionService versionService;
    @Autowired
    private CodeUtils codeUtils;

    @Value("${mail.fromMail.sender}")
    private String FROM;

    public CommitTestServiceImpl(CommitTestDao commitTestDao, CommitTraceDao commitTraceDao,
                                 AttachmentDao attachmentDao, UserStore userStore, MailUtils mailUtils,
                                 UserDao userDao, VersionDao versionDao, AppDao appDao,
                                 BackupTestUserDao backupTestUserDao, SubscribeDao subscribeDao,
                                 UserService userService, CommitContextService commitContextService, ExcellUtil excellUtil, CommitContextDao commitContextDao, VersionInfoDao versionInfoDao, CommitTraceService commitTraceService, AttachmentService attachmentService, AppService appService, VersionService versionService) {
        this.commitTestDao = commitTestDao;
        this.commitTraceDao = commitTraceDao;
        this.attachmentDao = attachmentDao;
        this.userStore = userStore;
        this.mailUtils = mailUtils;
        this.userDao = userDao;
        this.versionDao = versionDao;
        this.appDao = appDao;
        this.backupTestUserDao = backupTestUserDao;
        this.subscribeDao = subscribeDao;
        this.userService = userService;
        this.commitContextService = commitContextService;
        this.excellUtil = excellUtil;
        this.commitContextDao = commitContextDao;
        this.versionInfoDao = versionInfoDao;
        this.commitTraceService = commitTraceService;
        this.attachmentService = attachmentService;
        this.appService = appService;
        this.versionService = versionService;
    }

    @Override
    public BaseDao<CommitTestEntity, BigInteger> getDao() {
        return commitTestDao;
    }

    //<!--用户自定义代码开始-->

    /**
     * 开始提测/重新提测
     *
     * @param commitOrReCommitDto [com.yonyougov.devops.cruxcisupport.committest.dto.CommitOrReCommitDto]
     * @return 追踪表记录id
     */
    @Transactional
    @Override
    public BigInteger commitOrReCommit(CommitOrReCommitDto commitOrReCommitDto) throws Exception {
        // 主单实体类
        CommitTestEntity commitTestEntity = new CommitTestEntity();
        BeanUtils.copyProperties(commitOrReCommitDto, commitTestEntity);

        //状态检测 只允许处于驳回状态的提测单重新提测
        if (commitTestEntity.getId() != null) {
            CommitTestEntity commitTestEntityForQuery = new CommitTestEntity();
            commitTestEntityForQuery.setId(commitTestEntity.getId());
            CommitTestEntity result = commitTestDao.findBy(commitTestEntityForQuery);
            if (result == null || TestStatusEnum.TEST_REJECT.getValue() != result.getStatus()) {
                throw new Exception("状态错误");
            }
        }

        // 主提测单入库
        commitTestEntity.setCreateTime(new Date());
        commitTestEntity.setStartTime(new Date());
        commitTestEntity.setTestType(commitOrReCommitDto.getTestType());
        commitTestEntity.setStatus(TestStatusEnum.COMMIT_START.getValue());
        if (commitTestEntity.getId() == null) {
            // 生成提测code
            commitTestEntity.setCode(codeUtils.genCommitTestCode());
            // 新增提测单
            add(commitTestEntity);
        } else {
            update(commitTestEntity);
        }
        // 提测服务入库
        commitContextService.deleteByCommitTestId(commitTestEntity.getId());
        commitContextService.AddMulCommitContext(commitTestEntity.getId(), commitOrReCommitDto.getCommitContext());
        // 提测追踪入库
        BigInteger traceId = createCommitTrace(commitTestEntity, commitOrReCommitDto.getAttachmentUrls());
        // 发送开始提测邮件
        SendCreateOrConfirmMailThread sendMailThread = new SendCreateOrConfirmMailThread(
                mailUtils, commitTestEntity.getId(), subscribeDao,
                commitTestDao, commitContextService,
                this.FROM, commitTestEntity.getTestContent(), userDao,
                userStore.getCurrentUser().getUserName(), commitOrReCommitDto.getAttachmentUrls(), commitTestEntity.getStatus(),
                new ArrayList<>(), excellUtil);
        sendMailThread.start();
        return traceId;
    }

    /**
     * 需求功能确认(还没搞完)
     *
     * @param id             提测id
     * @param attachmentUrls 附件路径
     * @return 成功/失败
     */
    @Override
    public boolean funcConfirm(BigInteger id, List<String> attachmentUrls) {
        // 更改状态
        CommitTestEntity commitTestEntityForQuery = new CommitTestEntity();
        commitTestEntityForQuery.setId(id);
        CommitTestEntity result = commitTestDao.findBy(commitTestEntityForQuery);
        if (result != null) {
            result.setStatus(TestStatusEnum.COMMIT_START.getValue());
            update(result);
            // 发送邮件
            SendCreateOrConfirmMailThread sendMailThread = new SendCreateOrConfirmMailThread(
                    mailUtils, result.getId(), subscribeDao,
                    commitTestDao, commitContextService,
                    this.FROM, result.getRemark(), userDao,
                    userStore.getCurrentUser().getUserName(), attachmentUrls, result.getStatus(),
                    new ArrayList<>(), excellUtil);
            sendMailThread.start();
        } else {
            return false;
        }
        return true;
    }

    /**
     * 开始测试
     *
     * @param commitTestId 提测单id
     */
    @Override
    public void startTest(BigInteger commitTestId) {
        CommitTestEntity commitTestEntity = new CommitTestEntity();
        commitTestEntity.setId(commitTestId);
        commitTestEntity.setStatus(TestStatusEnum.TEST_START.getValue());
        commitTestDao.updateByPrimaryKey(commitTestEntity);

        CommitTraceEntity traceEntity = new CommitTraceEntity();
        traceEntity.setCreateTime(new Date());
        traceEntity.setId(new CruxDevOpsIdGenerator().generatorId(commitTraceDao));
        traceEntity.setCommitTestId(commitTestId);
        traceEntity.setRemark(TestStatusEnum.TEST_START.getName());
        traceEntity.setStatus(commitTestEntity.getStatus());
        traceEntity.setOperatorId(userStore.getCurrentUser().getId());
        commitTraceDao.insert(traceEntity);
    }

    /**
     * 提测驳回
     *
     * @param rejectCommitTestDto [com.yonyougov.devops.cruxcisupport.committest.dto.RejectCommitTestDto]
     * @return boolean
     */
    @Override
    public boolean rejectCommitTest(RejectCommitTestDto rejectCommitTestDto) {
        BigInteger commitTestId = rejectCommitTestDto.getId();
        String remark = rejectCommitTestDto.getRemark();
        List<String> attachmentUrls = rejectCommitTestDto.getAttachmentUrls();
        int status = TestStatusEnum.TEST_REJECT.getValue();
        return handleRejectOrPassOrReleaseCommitTest(commitTestId, attachmentUrls, remark, status, new ArrayList<>(), new ArrayList<>());
    }

    /**
     * 提测单作废
     *
     * @param commitTestid 提测单id
     */
    @Override
    public void invalidOneCommitTest(BigInteger commitTestid) {
        CommitTestEntity commitTestEntity = new CommitTestEntity();
        commitTestEntity.setId(commitTestid);
        commitTestEntity.setStatus(TestStatusEnum.TEST_DELETE.getValue());
        commitTestEntity.setEndTime(new Date());
        commitTestDao.updateByPrimaryKey(commitTestEntity);

        CommitTraceEntity traceEntity = new CommitTraceEntity();
        traceEntity.setCreateTime(new Date());
        traceEntity.setId(new CruxDevOpsIdGenerator().generatorId(commitTraceDao));
        traceEntity.setCommitTestId(commitTestid);
        traceEntity.setRemark(TestStatusEnum.TEST_DELETE.getName());
        traceEntity.setStatus(commitTestEntity.getStatus());
        traceEntity.setOperatorId(userStore.getCurrentUser().getId());
        commitTraceDao.insert(traceEntity);
    }

    /**
     * 测试通过
     *
     * @param passCommitTestDto [com.yonyougov.devops.cruxcisupport.committest.dto.PassCommitTestDto]
     * @return boolean
     */
    @Override
    public boolean passCommitTest(PassCommitTestDto passCommitTestDto) {
        BigInteger commitTestId = passCommitTestDto.getId();
        String remark = passCommitTestDto.getRemark();
        List<String> attachmentUrls = passCommitTestDto.getAttachmentUrls();
        int status = TestStatusEnum.TEST_SUCCESS.getValue();
        return handleRejectOrPassOrReleaseCommitTest(commitTestId, attachmentUrls, remark, status, new ArrayList<>(), new ArrayList<>());
    }

    ///**
    // * 提测流程发版
    // *
    // * @param releaseCommitTestDto [com.yonyougov.devops.cruxcisupport.committest.dto.ReleaseCommitTestDto]
    // * @return boolean
    // */
    //@Override
    //@Transactional
    //public boolean releaseCommitTest(ReleaseCommitTestDto releaseCommitTestDto) throws Exception {
    //
    //    // 查出提测数据
    //    CommitTestEntity resultCommitTestEntity = commitTestDao.findBy(CommitTestEntity.builder().id(releaseCommitTestDto.getId()).build());
    //    List<CommitContextEntity> commitContextEntityList = commitContextDao.findAllBy(CommitContextEntity.builder().commitTestId(releaseCommitTestDto.getId()).build());
    //
    //    // 发版前检查
    //    checkReleaseBefore(resultCommitTestEntity);
    //
    //    // 提测id
    //    BigInteger commitTestId = releaseCommitTestDto.getId();
    //    // 备注
    //    String remark = releaseCommitTestDto.getRemark();
    //    // 附件
    //    List<String> attachmentUrls = releaseCommitTestDto.getAttachmentUrls();
    //    // 自定义收件人
    //    List<BigInteger> selfDefineUserIds = releaseCommitTestDto.getUserIds();
    //
    //    // 生成excell附件
    //    List<String> excellPaths = Collections.singletonList(excellUtil.cruxVersionUp(releaseCommitTestDto));
    //
    //    //更新提测单的结束时间
    //    CommitTestEntity commitTestEntityForUpdate = new CommitTestEntity();
    //    commitTestEntityForUpdate.setId(releaseCommitTestDto.getId());
    //    commitTestEntityForUpdate.setEndTime(new Date());
    //    commitTestDao.updateByPrimaryKey(commitTestEntityForUpdate);
    //    // 设置状态
    //    resultCommitTestEntity.setStatus(TestStatusEnum.RELEASE.getValue());
    //    // 进入发版流程
    //    handleRejectOrPassOrReleaseCommitTest(commitTestId, attachmentUrls, remark, resultCommitTestEntity.getStatus(), selfDefineUserIds, excellPaths);
    //    // 发版后信息同步到版本描述
    //    synchroToVersionInfo(releaseCommitTestDto, resultCommitTestEntity, commitContextEntityList);
    //    return true;
    //}

    /**
     * 预发版
     *
     * @param releaseCommitTestPlusDto com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseCommitTestPlusDto
     * @param outputStream             javax.servlet.ServletOutputStream
     */
    @SneakyThrows
    @Override
    public void preReleaseCommitTest(ReleaseCommitTestDto releaseCommitTestPlusDto, ServletOutputStream outputStream) {
        String excellPath = genReleaseExcell(releaseCommitTestPlusDto);
        // 填充到响应流
        outputStream.write(FileUtils.readFileToByteArray(new File(excellPath)));
        outputStream.close();
    }

    /**
     * 提测流程发版
     *
     * @param releaseCommitTestPlusDto com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseCommitTestPlusDto
     * @return true/false
     */
    @SneakyThrows
    @Transactional
    @Override
    public boolean releaseCommitTestPlus(ReleaseCommitTestDto releaseCommitTestPlusDto) {
        String excellPath = genReleaseExcell(releaseCommitTestPlusDto);

        // 查出提测数据
        CommitTestEntity resultCommitTestEntity = commitTestDao.findBy(CommitTestEntity.builder().id(releaseCommitTestPlusDto.getId()).build());

        // 发版前检查
        checkReleaseBefore(resultCommitTestEntity);

        // 提测id
        BigInteger commitTestId = releaseCommitTestPlusDto.getId();
        // 备注
        String remark = releaseCommitTestPlusDto.getRemark();
        // 附件
        List<String> attachmentUrls = releaseCommitTestPlusDto.getAttachmentUrls();
        // 自定义收件人
        List<BigInteger> selfDefineUserIds = releaseCommitTestPlusDto.getUserIds();

        // 生成excell附件
        List<String> excellPaths = Collections.singletonList(excellPath);

        //更新提测单的结束时间
        CommitTestEntity commitTestEntityForUpdate = new CommitTestEntity();
        commitTestEntityForUpdate.setId(releaseCommitTestPlusDto.getId());
        commitTestEntityForUpdate.setEndTime(new Date());
        commitTestDao.updateByPrimaryKey(commitTestEntityForUpdate);
        //更新提测内容表中的 正式版本id 和 客户验证版本id
        releaseCommitTestPlusDto.getCommitTestAppList().forEach(e -> {
            CommitContextEntity commitContextEntity = commitContextService.findBy(CommitContextEntity.builder().id(e.getId()).build());
            if (versionService.exist(e.getMasterVersionId())) {
                commitContextEntity.setMasterVersionId(e.getMasterVersionId());
            }
            if (versionService.exist(e.getKhyzVersionId())) {
                commitContextEntity.setKhyzVersionId(e.getKhyzVersionId());
            }
            commitContextService.update(commitContextEntity);
        });

        // 设置状态
        resultCommitTestEntity.setStatus(TestStatusEnum.RELEASE.getValue());
        // 进入发版流程
        handleRejectOrPassOrReleaseCommitTest(commitTestId, attachmentUrls, remark, resultCommitTestEntity.getStatus(), selfDefineUserIds, excellPaths);
        // 发版后信息同步到版本描述
        synchroToVersionInfo(releaseCommitTestPlusDto, resultCommitTestEntity);
        return true;
    }

    /**
     * 处理驳回 通过 发版流程
     *
     * @param commitTestId   提测Id
     * @param attachmentUrls 附件路径集合
     * @param remark         描述
     * @param status         状态
     * @param toUserList     自定义邮件接收人
     * @return boolean
     */
    private boolean handleRejectOrPassOrReleaseCommitTest(BigInteger commitTestId, List<String> attachmentUrls,
                                                          String remark, int status,
                                                          List<BigInteger> toUserList, List<String> excellPaths) {
        try {
            BigInteger currentUserId = userStore.getCurrentUser().getId();
            String currentUserName = userStore.getCurrentUser().getUserName();
            //更新提测表的状态
            CommitTestEntity commitTestEntity = new CommitTestEntity();
            commitTestEntity.setId(commitTestId);
            commitTestEntity.setStatus(status);
            commitTestDao.updateByPrimaryKey(commitTestEntity);
            //向提测追踪表中新增记录
            CommitTraceEntity commitTraceEntity = new CommitTraceEntity();
            commitTraceEntity.setId(new CruxDevOpsIdGenerator().generatorId(commitTraceDao));
            commitTraceEntity.setCommitTestId(commitTestId);
            commitTraceEntity.setOperatorId(currentUserId);
            commitTraceEntity.setRemark(remark);
            commitTraceEntity.setStatus(status);
            commitTraceEntity.setCreateTime(new Date());
            commitTraceDao.insert(commitTraceEntity);
            //如果驳回时或者通过或者发版时，上传附件，在附件表中新增记录
            if (null != attachmentUrls && attachmentUrls.size() > 0) {
                List<AttachmentEntity> attachmentEntityList = attachmentUrls.stream().map(attachmentUrl -> {
                    AttachmentEntity attachmentEntity = new AttachmentEntity();
                    attachmentEntity.setId(new CruxDevOpsIdGenerator().generatorId(attachmentDao));
                    attachmentEntity.setAttachmentUrl(attachmentUrl);
                    attachmentEntity.setCreateTime(new Date());
                    attachmentEntity.setUserId(currentUserId);
                    attachmentEntity.setTranceId(commitTraceEntity.getId());
                    return attachmentEntity;
                }).collect(Collectors.toList());
                //批量插入附件表
                attachmentDao.batchInsert(attachmentEntityList);
            }
            // 发送邮件
            SendRejectOrPassOrReleaseMailThread sendMailThread = new SendRejectOrPassOrReleaseMailThread(mailUtils, commitTestId, subscribeDao, versionDao, commitTestDao,
                    appDao, this.FROM, remark, backupTestUserDao, userDao, currentUserName, attachmentUrls, status, toUserList, excellPaths, commitContextService);
            sendMailThread.start();
        } catch (Exception e) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            log.info("catch Exception when reject test is {}", sw.toString());
            return false;
        }
        return true;
    }

    /**
     * 发版前检查
     *
     * @param commitTestEntity 提测实体类
     */
    private void checkReleaseBefore(CommitTestEntity commitTestEntity) throws Exception {
        if (commitTestEntity.getStatus() != TestStatusEnum.TEST_SUCCESS.getValue()) {
            if (commitTestEntity.getStatus() == TestStatusEnum.RELEASE.getValue()) {
                log.error("提测单id={} 已经处于发版状态", commitTestEntity.getId());
            } else {
                log.error("提测单id={} 必须测试通过才能发版", commitTestEntity.getId());
            }
            throw new Exception("[发版异常]");
        }
    }

    /**
     * 生成发版excell
     *
     * @param releaseCommitTestPlusDto com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseCommitTestPlusDto
     * @return java.lang.String
     */
    @SneakyThrows
    private String genReleaseExcell(ReleaseCommitTestDto releaseCommitTestPlusDto) {
        // 入参
        @NotNull BigInteger commitTestId = releaseCommitTestPlusDto.getId();
        @NotEmpty String newAndPtimizeContent = releaseCommitTestPlusDto.getNewAndPtimizeContent();
        List<ReleaseContextRequestDto> commitTestAppList = releaseCommitTestPlusDto.getCommitTestAppList();
        String testSuggest = releaseCommitTestPlusDto.getTestSuggest();

        // 数据库查询
        CommitTestEntity commitTestEntity = findBy(CommitTestEntity.builder().id(commitTestId).build());

        // 组装数据
        List<CruxVersionUpEntity> list = new ArrayList<>();
        for (ReleaseContextRequestDto e : commitTestAppList) {
            if (versionService.exist(e.getMasterVersionId())) {
                CommitContextEntity commitContextEntity = commitContextService.findBy(CommitContextEntity.builder().id(e.getId()).build());
                AppEntity appEntity = appService.findBy(AppEntity.builder().id(commitContextEntity.getAppId()).build());
                VersionEntity masterVersionEntity = versionService.findBy(VersionEntity.builder().id(e.getMasterVersionId()).build());

                CruxVersionUpEntity item = new CruxVersionUpEntity();
                item.setSheetName(appEntity.getApp() + " ( master分支 ) ");
                item.setProductName(commitTestEntity.getProductName());
                item.setAppName(appEntity.getApp());
                item.setVersion(masterVersionEntity.getVersionName());
                item.setNewAndPtimizeContent(newAndPtimizeContent);
                item.setCruxVersionUpAskEntities(Lists.newArrayList());
                List<CruxVersionUpBugFixRemarkEntity> cruxVersionUpBugFixRemarkEntities = new ArrayList<>();
                cruxVersionUpBugFixRemarkEntities.add(CruxVersionUpBugFixRemarkEntity.builder().bugId(commitTestEntity.getBugId()).bugRemark(commitTestEntity.getBugDesc()).build());
                item.setCruxVersionUpBugFixRemarkEntities(cruxVersionUpBugFixRemarkEntities);
                List<CruxVersionUpNewAddFuncRemarkEntity> cruxVersionUpNewAddFuncRemarkEntity = new ArrayList<>();
                cruxVersionUpNewAddFuncRemarkEntity.add(CruxVersionUpNewAddFuncRemarkEntity.builder().remark(commitTestEntity.getFunDesc()).build());
                item.setCruxVersionUpNewAddFuncRemarkEntities(cruxVersionUpNewAddFuncRemarkEntity);
                item.setCruxVersionUpStressTestAskEntities(Lists.newArrayList());
                item.setPerformTestAsks(Lists.newArrayList());
                item.setTestSuggest(testSuggest);
                list.add(item);
            } else {
                throw new Exception("版本: " + e.getMasterVersionId() + " 不存在");
            }
            if (null != e.getKhyzVersionId()) {
                if (!versionService.exist(e.getKhyzVersionId())) {
                    throw new Exception("版本: " + e.getKhyzVersionId() + " 不存在");
                }
                CommitContextEntity commitContextEntity = commitContextService.findBy(CommitContextEntity.builder().id(e.getId()).build());
                AppEntity appEntity = appService.findBy(AppEntity.builder().id(commitContextEntity.getAppId()).build());
                VersionEntity masterVersionEntity = versionService.findBy(VersionEntity.builder().id(e.getKhyzVersionId()).build());

                CruxVersionUpEntity item = new CruxVersionUpEntity();
                item.setSheetName(appEntity.getApp() + " ( khyz分支 ) ");
                item.setProductName(commitTestEntity.getProductName());
                item.setAppName(appEntity.getApp());
                item.setVersion(masterVersionEntity.getVersionName());
                item.setNewAndPtimizeContent(newAndPtimizeContent);
                item.setCruxVersionUpAskEntities(Lists.newArrayList());
                List<CruxVersionUpBugFixRemarkEntity> cruxVersionUpBugFixRemarkEntities = new ArrayList<>();
                cruxVersionUpBugFixRemarkEntities.add(CruxVersionUpBugFixRemarkEntity.builder().bugId(commitTestEntity.getBugId()).bugRemark(commitTestEntity.getBugDesc()).build());
                item.setCruxVersionUpBugFixRemarkEntities(cruxVersionUpBugFixRemarkEntities);
                List<CruxVersionUpNewAddFuncRemarkEntity> cruxVersionUpNewAddFuncRemarkEntity = new ArrayList<>();
                cruxVersionUpNewAddFuncRemarkEntity.add(CruxVersionUpNewAddFuncRemarkEntity.builder().remark(commitTestEntity.getFunDesc()).build());
                item.setCruxVersionUpNewAddFuncRemarkEntities(cruxVersionUpNewAddFuncRemarkEntity);
                item.setCruxVersionUpStressTestAskEntities(Lists.newArrayList());
                item.setPerformTestAsks(Lists.newArrayList());
                item.setTestSuggest(testSuggest);
                list.add(item);
            }
        }
        // 生成excell模版
        return excellUtil.cruxRelease(list);
    }

    /**
     * 发版后信息同步到版本描述
     *
     * @param releaseCommitTestPlusDto com.yonyougov.devops.cruxcisupport.committest.dto.release.ReleaseCommitTestPlusDto
     * @param commitTestEntity         com.yonyougov.devops.cruxcisupport.committest.CommitTestEntity
     */
    private void synchroToVersionInfo(ReleaseCommitTestDto releaseCommitTestPlusDto, CommitTestEntity commitTestEntity) {
        List<VersionInfoEntity> needInsertVersionInfo = new ArrayList<>();
        releaseCommitTestPlusDto.getCommitTestAppList().forEach(e -> {
            // 主版本同步到版本描述
            if (null != e.getMasterVersionId()) {
                VersionInfoEntity versionInfoEntity = VersionInfoEntity.builder()
                        .id(new CruxDevOpsIdGenerator().generatorId(versionDao))
                        .createTime(new Date())
                        .type(EnumUtil.getValueByCode(commitTestEntity.getTestType(), TestTypeEnum.class))
                        .versionDesc(releaseCommitTestPlusDto.getRemark())
                        .versionId(e.getMasterVersionId())
                        .commitTestId(commitTestEntity.getId())
                        .build();
                needInsertVersionInfo.add(versionInfoEntity);
            }
            // 客户验证版本同步到版本描述
            if (null != e.getKhyzVersionId()) {
                VersionInfoEntity versionInfoEntity = VersionInfoEntity.builder()
                        .id(new CruxDevOpsIdGenerator().generatorId(versionDao))
                        .createTime(new Date())
                        .type(EnumUtil.getValueByCode(commitTestEntity.getTestType(), TestTypeEnum.class))
                        .versionDesc(releaseCommitTestPlusDto.getRemark())
                        .versionId(e.getKhyzVersionId())
                        .commitTestId(commitTestEntity.getId())
                        .build();
                needInsertVersionInfo.add(versionInfoEntity);
            }
        });
        // 处理 "版本描述表"
        versionInfoDao.batchInsert(needInsertVersionInfo);

        // 更改 提测单的"提测内容" 为 "版本描述"
        commitTestEntity.setTestContent(releaseCommitTestPlusDto.getRemark());
        update(commitTestEntity);
    }

    /**
     * 创建追踪记录
     *
     * @param commitTestEntity 提测主单实体
     * @return 追踪id
     */
    private BigInteger createCommitTrace(CommitTestEntity commitTestEntity, List<String> attachmentUrls) {
        // 追踪表新增
        CommitTraceEntity traceEntity = new CommitTraceEntity();
        traceEntity.setCreateTime(commitTestEntity.getCreateTime());
        traceEntity.setCommitTestId(commitTestEntity.getId());
        traceEntity.setRemark(commitTestEntity.getRemark());
        traceEntity.setStatus(commitTestEntity.getStatus());
        traceEntity.setOperatorId(userStore.getCurrentUser().getId());
        commitTraceService.add(traceEntity);
        // 附件表新增
        createAttachment(traceEntity.getId(), commitTestEntity.getSubmitUserId(), attachmentUrls);
        return traceEntity.getId();
    }

    /**
     * 附件入库
     * @param traceId        追踪id
     * @param submitUserId   提测人id
     * @param attachmentUrls 附件列表
     */
    private void createAttachment(BigInteger traceId, BigInteger submitUserId, List<String> attachmentUrls) {
        if (null == traceId || null == submitUserId || null == attachmentUrls || attachmentUrls.size() == 0) {
            return;
        }
        List<AttachmentEntity> attachmentEntities = attachmentUrls.stream().map(att -> {
            AttachmentEntity a = new AttachmentEntity();
            a.setId(new CruxDevOpsIdGenerator().generatorId(attachmentDao));
            a.setTranceId(traceId);
            a.setUserId(submitUserId);
            a.setCreateTime(new Date());
            a.setAttachmentUrl(att);
            return a;
        }).collect(Collectors.toList());
        attachmentService.addBatch(attachmentEntities);
    }

    /**
     * 提测列表页面
     *
     * @param queryListDto [com.yonyougov.devops.cruxcisupport.committest.vo.QueryCommitStartPageDto]
     * @return [java.util.Map]
     */
    @Override
    public Pagination<QueryCommitTestVo> query(QueryListDto queryListDto) {
        Map<String, Object> result = new HashMap<>();
        int totalCount;
        List<QueryCommitTestVo> datas;
        //获取当前用户信息
        UserEntity currentUser = userService.getCurrentUser();
        if (null == queryListDto.getCurrentUserId()) {
            queryListDto.setCurrentUserId(currentUser.getId());
        }
        //获取当前用户拥有的角色列表
        List<String> roleNames = userStore.currentUserRoles().stream().map(RoleEntity::getRoleName).collect(Collectors.toList());
        //当前用户包含admin角色，查询全部
        if (roleNames.contains("admin")) {
            totalCount = commitTestDao.countByAdmin(queryListDto);
            datas = commitTestDao.findAllByAdmin(queryListDto);
        } else {
            //当前用户是测试人员
            if (UserOfficeTypeEnum.TESTER.equals(currentUser.getOfficeType())) {
                totalCount = commitTestDao.countByTest(queryListDto);
                datas = commitTestDao.findAllByTest(queryListDto);
            } else {
                //当前用户是开发人员
                totalCount = commitTestDao.countByDevelop(queryListDto);
                datas = commitTestDao.findAllByDevelop(queryListDto);
            }
        }
        log.info("totalCount is {}", totalCount);
        log.info("data is {}", datas);
        return new Pagination<QueryCommitTestVo>(queryListDto.getMax(), queryListDto.getPageNum(), totalCount, datas);
    }

    /**
     * 更改提测单
     * 根据当前用户权限
     *
     * @param updateCommitTestByCurrentUserPermissionDto [com.yonyougov.devops.cruxcisupport.committest.dto.UpdateCommitTestByCurrentUserPermissionDto]
     * @author gaoziteng
     */
    @Override
    @Transactional
    public void updateCommitTestByCurrentUserPermission(UpdateCommitTestByCurrentUserPermissionDto updateCommitTestByCurrentUserPermissionDto) throws Exception {
        BigInteger commitTestId = updateCommitTestByCurrentUserPermissionDto.getCommitTestId();
        BigInteger envId = updateCommitTestByCurrentUserPermissionDto.getEnvId();
        String testContent = updateCommitTestByCurrentUserPermissionDto.getTestContent();
        String remark = updateCommitTestByCurrentUserPermissionDto.getRemark();

        UserEntity currentUser = userService.findBy(UserEntity.builder().id(userStore.getCurrentUser().getId()).build());
        CommitTestEntity commitTestEntity = commitTestDao.findBy(CommitTestEntity.builder().id(commitTestId).build());
        // 没有发版之前 测试内容和备注 允许测试人员和管理人员修改
        if (!commitTestEntity.getStatus().equals(TestStatusEnum.RELEASE.getValue()) && !commitTestEntity.getStatus().equals(TestStatusEnum.TEST_DELETE.getValue())) {
            if (UserOfficeTypeEnum.TESTER.equals(currentUser.getOfficeType()) || UserOfficeTypeEnum.MANAGE.equals(currentUser.getOfficeType())) {
                CommitTestEntity forSave = CommitTestEntity.builder().id(commitTestEntity.getId()).envId(envId).testContent(testContent).remark(remark).build();
                updateByPrimaryKey(forSave);
                return;
            }
            throw new Exception("用户权限不足");
        }
        // 发版之后 只有管理人员能修改
        if (commitTestEntity.getStatus().equals(TestStatusEnum.RELEASE.getValue())) {
            if (UserOfficeTypeEnum.MANAGE.equals(currentUser.getOfficeType())) {
                CommitTestEntity forSave = CommitTestEntity.builder().id(commitTestEntity.getId()).envId(envId).testContent(testContent).remark(remark).build();
                updateByPrimaryKey(forSave);
                return;
            }
            throw new Exception("用户权限不足");
        }
        throw new Exception("提测单状态不正确");
    }

    /**
     * 今天提测数
     *
     * @return Long
     */
    @Override
    public Long todayCommitTestNumber() {
        return commitTestDao.todayCommitTestNumber();
    }

    /**
     * 统计驳回页
     *
     * @param statisticsRejectedDto com.yonyougov.devops.cruxcisupport.committest.dto.StatisticsRejectedDto
     * @return com.yonyougov.devops.fwc.core.entity.Pagination
     */
    @Override
    public Pagination<StatisticsRejectedVo> statisticsRejected(StatisticsRejectedDto statisticsRejectedDto) {
        List<StatisticsRejectedVo> datas = commitTestDao.statisticsRejected(statisticsRejectedDto);
        int totalCount = commitTestDao.statisticsRejectedCount(statisticsRejectedDto);

        // 计算耗时,写入datas
        if (CollectionUtils.isNotEmpty(datas)) {
            // 获取上述提测单所涉及到的所有追踪记录
            List<CommitTraceEntity> allCommitTraceEntityList = commitTraceService.findByIn(CommitTraceEntityByInDto.builder().commitTestIdIn(datas.stream().map(StatisticsRejectedVo::getSubmitTestId).collect(Collectors.toList())).build());
            // 按照提测id分组
            Map<BigInteger, List<CommitTraceEntity>> mapByCommitTestId = allCommitTraceEntityList.stream().collect(Collectors.groupingBy(CommitTraceEntity::getCommitTestId));
            // 遍历各组追踪记录计算耗时
            for (StatisticsRejectedVo data : datas) {
                int totalSumTime = 0;// 当前提测单的驳回修改的总耗时
                List<String> consumTimeVoList = new ArrayList<>();// 当前提测单的驳回修改的分片耗时
                List<CommitTraceEntity> commitTraceEntityList = mapByCommitTestId.get(data.getSubmitTestId());
                if (commitTraceEntityList.size() > 1) {
                    for (int i = 1; i < commitTraceEntityList.size(); i++) {
                        if (TestStatusEnum.COMMIT_START.getValue() == commitTraceEntityList.get(i).getStatus()) {
                            Date commitTestDate = commitTraceEntityList.get(i - 1).getCreateTime();
                            Date rejectDate = commitTraceEntityList.get(i).getCreateTime();
                            int diffTime = Integer.parseInt("" + (rejectDate.getTime() - commitTestDate.getTime()) / 1000);
                            totalSumTime += diffTime;
                            consumTimeVoList.add(DateUtils.convert(diffTime));
                        }
                    }
                }
                data.setConsumeTime(DateUtils.convert(totalSumTime));
                data.setSegConsumeTimeList(consumTimeVoList);
            }
        }

        // 没有code则将提测id设置为code
        for (StatisticsRejectedVo data : datas) {
            if (StringUtils.isBlank(data.getSubmitTestCode())) {
                data.setSubmitTestCode(data.getSubmitTestId().toString());
            }
        }
        return new Pagination<>(statisticsRejectedDto.getMax(), statisticsRejectedDto.getPageNum(), totalCount, datas);
    }

    /**
     * 统计提测页
     *
     * @param statisticsCommitTestDto com.yonyougov.devops.cruxcisupport.committest.dto.StatisticsCommitTestDto
     * @return com.yonyougov.devops.fwc.core.entity.Pagination
     */
    @Override
    public Pagination<StatisticsCommitTestVo> statisticsCommitTest(StatisticsCommitTestDto statisticsCommitTestDto) {
        // 查询需要统计的提测
        List<StatisticsCommitTestVo> datas = commitTestDao.statisticsCommitTest(statisticsCommitTestDto);
        int totalCount = commitTestDao.statisticsCommitTestCount(statisticsCommitTestDto);

        // 计算耗时,写入datas
        if (CollectionUtils.isNotEmpty(datas)) {
            // 按照提测id和状态In查询创建时间(如果在某个提测某个状态下取到多条记录,则按照默认排序取第一条)
            List<CommitTraceKeyValueVo> groupByCommitTestIdStatus = commitTraceService.findGroupByCommitTestIdStatus(CommitTestIdInStatusInDto.builder()
                    .commitTestIdIn(datas.stream().map(StatisticsCommitTestVo::getCommitTestId).collect(Collectors.toList()))
                    .statusIn(Arrays.asList(statisticsCommitTestDto.getStartStatus(), statisticsCommitTestDto.getEndStatus()))
                    .build());
            // 转map
            Map<String, Date> map = groupByCommitTestIdStatus.stream().collect(Collectors.toMap(CommitTraceKeyValueVo::getTkey, CommitTraceKeyValueVo::getCreateTime));
            // 写入耗时到datas
            for (StatisticsCommitTestVo data : datas) {
                data.setConsumeTime(DateUtils.convert(Integer.parseInt(String.valueOf((map.get("" + data.getCommitTestId() + statisticsCommitTestDto.getEndStatus()).getTime() - map.get("" + data.getCommitTestId() + statisticsCommitTestDto.getStartStatus()).getTime()) / 1000))));
            }
        }

        // 补充code
        for (StatisticsCommitTestVo data : datas) {
            if (StringUtils.isBlank(data.getCommitTestCode())) {
                data.setCommitTestCode(data.getCommitTestId() + "");
            }
        }
        return new Pagination<>(statisticsCommitTestDto.getMax(), statisticsCommitTestDto.getPageNum(), totalCount, datas);
    }

    /**
     * 驳回耗时按钮
     *
     * @param statisticsRejectedConsumeTimeDto com.yonyougov.devops.cruxcisupport.committest.dto.StatisticsRejectedConsumeTimeDto
     * @return java.util.List
     */
    @Override
    public List<StatisticsRejectedConsumeTimeVo> statisticsRejectedConsumeTime(StatisticsRejectedConsumeTimeDto statisticsRejectedConsumeTimeDto) {
        CommitTestIdAndStatusDto commitTestIdAndStatusDto = new CommitTestIdAndStatusDto();
        commitTestIdAndStatusDto.setCommitTestId(statisticsRejectedConsumeTimeDto.getCommitTestId());
        commitTestIdAndStatusDto.setStatusIn(Arrays.asList(TestStatusEnum.COMMIT_START.getValue(), TestStatusEnum.TEST_REJECT.getValue()));

        List<CommitTraceEntity> datas = commitTraceService.findByCommitTestIdAndStatus(commitTestIdAndStatusDto);
        List<StatisticsRejectedConsumeTimeVo> consumTimeVoList = new ArrayList<>();
        if (datas.size() > 1) {
            for (int i = 1; i < datas.size(); i++) {
                if (TestStatusEnum.COMMIT_START.getValue() == datas.get(i).getStatus()) {
                    Date commitTestDate = datas.get(i - 1).getCreateTime();
                    Date rejectDate = datas.get(i).getCreateTime();
                    consumTimeVoList.add(StatisticsRejectedConsumeTimeVo.builder().consumTime(DateUtils.convert(Integer.parseInt("" + (rejectDate.getTime() - commitTestDate.getTime()) / 1000))).build());
                }
            }
        }
        return consumTimeVoList;
    }

    /**
     * 根据提测id或者提测code唯一确定一个提测单
     * 提测id和提测code至少存在一个,如若都存在,走提测id
     *
     * @param queryDto com.yonyougov.devops.cruxcisupport.committest.dto.QueryCommitTestDto
     * @return com.yonyougov.devops.cruxcisupport.committest.vo.QueryCommitTestVo
     */
    @Override
    public QueryCommitTestVo query(QueryDto queryDto) throws Exception {
        BigInteger commitTestId = queryDto.getCommitTestId();
        String commitTestCode = queryDto.getCommitTestCode();
        queryDto.setCommitTestId(null);
        queryDto.setCommitTestCode(null);
        if (Objects.nonNull(commitTestId)) {
            queryDto.setCommitTestId(commitTestId);
        } else if (StringUtils.isNotBlank(commitTestCode)) {
            queryDto.setCommitTestCode(commitTestCode);
        } else {
            throw new Exception("提测id和提测code至少传入一个");
        }
        return commitTestDao.queryCommitTest(queryDto);
    }


    //<!--用户自定义代码结束-->
}
